
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "nuclei_sdk_soc.h"
#include "dbg_cli.h"
#include "test_spi.h"
#include "test_iic.h"
#include "test_time.h"
#include "test_wdt.h"
#include "test_rtc.h"
#include "CRC_16_modbus.h"
#include "modbus.h"
#include "test_dma.h"
#include "test_uart.h"



uint32_t  read_reg( uintptr_t addr )
{
   return (*((volatile uint32_t *) (addr)));
}

void  write_reg( uintptr_t addr, uint32_t value )
{
  *(volatile uint32_t *)(addr) = value;
  return;
}

int getchar( void )
{
	return (int)(uint32_t)uart_read( UART2 );
}



/*
 *  incr = 0, get curr postion.
 *  incr > 0, alloc.
 *  ince < 0, free.
 */
extern char __heap_start[];
void * _sbrk( intptr_t incr )
{
	static intptr_t  heapos = (intptr_t)__heap_start;
	void * prepos = (void *)heapos;
	
	if ( incr > 0 )  {
		/* judge range, err for return (void *)(-1).. */
		heapos += incr;
	} else {
		heapos += incr;
	}
	
	/**/
	return prepos;
}



int dbg_test_cycle( void * parg, int argc, const char * argv[] )
{
	uint32_t temp;
	uint32_t told;
	uint32_t tnew;
	dw_timer_regs_t * ptmr = (dw_timer_regs_t *)TIMER0_BASE;


	__enable_mcycle_counter();
	

	/* timer config */	
	ptmr->TCR = 0;
	ptmr->TLC = 100000000ul;
	ptmr->TCR = 2;
	ptmr->TCR = 3;
	told = __RV_CSR_READ( CSR_MCYCLE );

	while ( true )  {
		temp = ptmr->TIS;
		if ( temp != 0 )  {
			tnew = __RV_CSR_READ( CSR_MCYCLE );
			ptmr->TCR = 0;
			temp = ptmr->TEOI;
			break;
		}
	}
	
	temp = tnew - told;
	printf( "cycle : %lu\n", temp );
	return 0;
}


/*
使用 uart-1 的 de 信号输出 toggle 波形.
*/
int dbg_test_toggle( void * parg, int argc, const char * argv[] )
{
	dw_uart_regs_t * puart = (dw_uart_regs_t *)UART1_BASE;

	/* pinmux */
	// REG32( 0x2000F4 ) = 0xFFF00;


	puart->TCR = 0x1;
	
	for ( int i=0; i<100; i++ )  {

		puart->DE_EN = 0x0;
		puart->RE_EN = 0x1;
		__NOP();
		__NOP();
		__NOP();

		puart->DE_EN = 0x1;
		puart->RE_EN = 0x0;
		__NOP();
		__NOP();
		__NOP();

	}
	
	return 0;
}




int dbg_test_mcfg( void * parg, int argc, const char * argv[] )
{
	uint32_t temp;
	
	temp = __RV_CSR_READ( CSR_MCFG_INFO );
	printf( "mcfg = %lx\n", temp );
	
	temp = __RV_CSR_READ( CSR_MICFG_INFO );
	printf( "micfg = %lx\n", temp );

	temp = __RV_CSR_READ( CSR_MDCFG_INFO );
	printf( "mdcfg = %lx\n", temp );
	
	temp = __RV_CSR_READ( CSR_MILM_CTL );
	printf( "milm = %lx\n", temp );

	temp = __RV_CSR_READ( CSR_MDLM_CTL );
	printf( "mdlm = %lx\n", temp );
	return 0;
}

int dbg_test_time( void * parg, int argc, const char * argv[] )
{

	//timer_case1();

	//timer_case2();//单次中断

	timer_case3();//多次中断
	

	return 0;
}


int dbg_rtc_time( void * parg, int argc, const char * argv[] )
{

	
	
	rtc_case2();
	
	return 0;
}

int dbg_wdt_time( void * parg, int argc, const char * argv[] )
{

	//wdt_case1(WDT_BASE);

	wdt_case2(WDT_BASE);

	return 0;


}

int dbg_test_modbus( void * parg, int argc, const char * argv[] )
{
	uint32_t  addr;
	uint32_t  num;
	uint32_t value;

	if ( argc != 3 )
	{
		goto usage;
	}
	
	debug_str2uint( argv[1], &addr );

	debug_str2uint( argv[2], &num );


	value = modbus_read(0x04,addr,num); //激光位移传感器读取距离
	if(value == -1||value == -2||value == -3){
		printf("modbus read error\n");
		return 0;
	}
	printf("距离: %ld.%ldmm\n",value/100,value%100);

	return 0;
	
usage:
	printf("usage: %s <addr> <num>\n", argv[0] );	
	return 0;
}


int dbg_test_crc( void * parg, int argc, const char * argv[] ){
	uint16_t crc;
	uint8_t data[] = {0x01,0x04,0x00,0x01,0x00,0x01};
	uint8_t len = 6;
	crc = CRC_Check(data,len);
	printf("CRC16-Modbus: 0x%04X\n",crc);
	return 0;	

}

//测试 DMA 传输 UART 
int dbg_test_dma_uart( void * parg, int argc, const char * argv[] ){
	uint32_t uart_num;
	if ( argc != 2 )
	{
		goto usage;
	}
	debug_str2uint( argv[1], &uart_num );

	if(uart_num == 0){

		dma_uart0_case();
	}
	else if (uart_num== 1)
	{
		dma_uart1_case();	
	}

	return 0;

	
usage:
	printf("usage: %s <uart_num> <0/1>\n", argv[0] );	
	return 0;
	}


//测试 DMA 传输 SPI
int dbg_test_dmaspi( void * parg, int argc, const char * argv[] ){


	dma_spi_case_tx();


	dma_spi_case_rx();
	
	

	return 0;
}

/**
 * @brief  测试 UART 
 */
int dbg_test_uart( void * parg, int argc, const char * argv[] ){
	uint32_t uart_num;

	if ( argc != 2 )
	{
		goto usage;
	}
	debug_str2uint( argv[1], &uart_num );

	if(uart_num == 0){
		// 环回测试
		uart_Loopback_test(UART0);
		// 数据位测试
		test_data_bits(UART0);
		// 奇偶校验测试
		test_parity(UART0);
		// 停止位配置验证
		test_stop_bits_config(UART0);

	}
	else if (uart_num== 1)
	{
		// 环回测试
		uart_Loopback_test(UART1);
		// 数据位测试
		test_data_bits(UART1);
		// 奇偶校验测试
		test_parity(UART1);
		// 停止位配置验证
		test_stop_bits_config(UART1);
	}

	return 0;

	
usage:
	printf("usage: %s <uart_num> <0/1>\n", argv[0] );	
	return 0;
}


int dbg_test_mod_srsten( void * parg, int argc, const char * argv[] ){

	dw_timer_regs_t *time0 = (dw_timer_regs_t *) TIMER0_BASE;
	dw_timer_regs_t *time1 = (dw_timer_regs_t *) TIMER1_BASE;
	dw_timer_regs_t *time2 = (dw_timer_regs_t *) TIMER2_BASE;
	dw_timer_regs_t *time3 = (dw_timer_regs_t *) TIMER3_BASE;
	dw_rtc_regs_t *rtc = (dw_rtc_regs_t *) RTC_BASE;
	dw_wdt_regs_t *wdt = (dw_wdt_regs_t *) WDT_BASE;
	dw_spi_regs_t *spim = (dw_spi_regs_t *) SPI0_BASE;
	dw_spi_regs_t *spis = (dw_spi_regs_t *) SPI1_BASE;


	//随意配置一个模式，修改了TIME寄存器的值
	timer_init_free_running(TIMER0_BASE);
	timer_init_free_running(TIMER1_BASE);
	timer_init_free_running(TIMER2_BASE);
	timer_init_free_running(TIMER3_BASE);

	//判断是否修改成功
	if((time0->TLC != 25000000) || (time1->TLC != 25000000) || (time2->TLC != 25000000) || (time3->TLC != 25000000)){
		printf("timer init error\n");
		return -1;
	}
	//TIME MOD SRSTEN
	write_reg(0x200004,0xffe1ffff);// mod time1 time2 time3 time4

	//判断是否实现了模式切换
	if((time0->TLC != 0) || (time1->TLC != 0) || (time2->TLC != 0) || (time3->TLC != 0)){
		printf("MOD_SRSTN error\n");	
		return -2;
	}

	rtc_case1(rtc);

	if( rtc->CMR !=1000000 ||rtc->CCR != 0x2){
		printf("RTC init error\n");
		return -3;
	}
	//RTC MOD SRSTEN
	write_reg(0x200004,0xffff7fff);

	//判断是否实现了模式切换
	if( rtc->CMR !=0 || rtc->CCR != 0){
		printf("MOD_SRSTN error\n");
		return -4;
	}

	wdt_case1(wdt);

	if(wdt->TORR != 0x4){
		printf("WDT init error\n");
		return -5;
	}
	//WDT MOD SRSTEN
	write_reg(0x200004,0xffffbfff);
	//判断是否实现了模式切换
	if( wdt->TORR != 0x0){
		printf("MOD_SRSTN error\n");
		return -6;
	}

	spi_case(spim);

	if(spim->CTRLR0 != 0xf){
		printf("SPI init error\n");
		return -7;
	}

	//SPI MOD SRSTEN
	write_reg(0x200004,0xfffffdff);
	//判断是否实现了模式切换
	if( spim->CTRLR0 != 0x0){
		printf("MOD_SRSTN error\n");
		return -8;
	}


	return 0;
}



int main( void )
{
	int iret;
	char spad[128];

	printf( "hello...\n" );
	debug_cli_init();
	debug_add_cmd( "cycle", dbg_test_cycle,  NULL );
	debug_add_cmd( "toggle", dbg_test_toggle,  NULL );
	debug_add_cmd( "mcfg", dbg_test_mcfg,  NULL );
	
	debug_add_cmd("spi", dbg_test_spi,  NULL );
	debug_add_cmd("spis",dbg_test_spi_slave,  NULL );

	debug_add_cmd("iicm", dbg_test_iic_maseter,  NULL );
	debug_add_cmd("iics", dbg_test_iic_slave,  NULL );

	debug_add_cmd("mod",dbg_test_mod_srsten,NULL);
	

	debug_add_cmd("time", dbg_test_time,  NULL );
	debug_add_cmd("rtc", dbg_rtc_time,  NULL );
	debug_add_cmd("wdt", dbg_wdt_time,  NULL );

	debug_add_cmd("dmauart", dbg_test_dma_uart,  NULL );

	debug_add_cmd("dmaspi", dbg_test_dmaspi,  NULL );

	debug_add_cmd("uart", dbg_test_uart, NULL);

	debug_add_cmd("modbus",dbg_test_modbus,NULL);
	debug_add_cmd("crc",dbg_test_crc,NULL);
	/**/
	while ( true )  {

		/* read line */
		iret = cons_readline( ">> ", 120, spad );
		if ( iret != 0 ) {
			continue;
		}
			
		if ( 0 == strcmp( spad, "quit" ) )  {
			break;
		}

		/* proc */
		debug_proc_line( spad );
	}

	/**/
	return 0;
}

